package com.deer.wms.ware.task.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.deer.wms.base.system.dao.ErpBackRecordMapper;
import com.deer.wms.base.system.dao.ItemInfoMapper;
import com.deer.wms.base.system.model.*;
import com.deer.wms.base.system.model.Area.AreaInfoDto;
import com.deer.wms.base.system.model.Item.ItemInfo;
import com.deer.wms.base.system.service.AreaInfoService;
import com.deer.wms.base.system.service.CellInfoService;
import com.deer.wms.base.system.service.ItemInfoService;
import com.deer.wms.busine.tactic.model.RouteTactic;
import com.deer.wms.busine.tactic.model.RouteTacticCriteria;
import com.deer.wms.busine.tactic.service.RouteTacticService;
import com.deer.wms.intercept.common.data.CurrentUser;
import com.deer.wms.inventory.constant.InventoryConstant;
import com.deer.wms.inventory.model.Inventory.Inventory;
import com.deer.wms.inventory.model.Inventory.InventoryCriteria;
import com.deer.wms.inventory.model.Inventory.InventorySelectDto;
import com.deer.wms.inventory.model.Inventory.InventoryTransact;
import com.deer.wms.inventory.service.InventoryService;
import com.deer.wms.inventory.service.InventoryTransactService;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.core.service.QueryCriteria;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.service.SuperServiceImpl;
import com.deer.wms.project.root.util.BeanUtils;
import com.deer.wms.project.root.util.DateUtils;
import com.deer.wms.review.manage.model.BillRecord;
import com.deer.wms.review.manage.service.BillRecordService;
import com.deer.wms.review.manage.service.CaseMasterService;
import com.deer.wms.system.manage.constant.SystemManageConstant;
import com.deer.wms.system.manage.dao.CustomerMapper;
import com.deer.wms.system.manage.model.DataDictDetail;
import com.deer.wms.system.manage.model.customer.Customer;
import com.deer.wms.system.manage.model.organization.Organization;
import com.deer.wms.system.manage.model.ware.WareInfo;
import com.deer.wms.system.manage.service.*;
import com.deer.wms.ware.task.config.StrategyErpService;
import com.deer.wms.ware.task.constant.WareTaskConstant;
import com.deer.wms.ware.task.dao.SoDetailMapper;
import com.deer.wms.ware.task.dao.SoMasterMapper;
import com.deer.wms.ware.task.model.SO.CreateSo.CreateSo;
import com.deer.wms.ware.task.model.SO.CreateSo.CreateSoDeliveryAddress;
import com.deer.wms.ware.task.model.SO.CreateSo.CreateSoShippingAddress;
import com.deer.wms.ware.task.model.SO.CreateSo.CreateSoSkuDetail;
import com.deer.wms.ware.task.model.SO.*;
import com.deer.wms.ware.task.model.SO.vo.SoDetailVo;
import com.deer.wms.ware.task.model.SO.vo.SoMasterVo;
import com.deer.wms.ware.task.model.Wave.WaveDetail;
import com.deer.wms.ware.task.model.out.OutDetail;
import com.deer.wms.ware.task.model.pickTask.PickTask;
import com.deer.wms.ware.task.model.pushErp.beasAssist.BaseAssist;
import com.deer.wms.ware.task.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.activation.DataHandler;
import java.util.*;
import java.util.stream.Collectors;

import static com.deer.wms.project.root.util.CollectionUtils.convertMap;

/**
 * Created by guo on 2020/02/02.
 */
@Service
@Transactional
public class SoMasterServiceImpl extends SuperServiceImpl<SoMasterMapper, SoMaster> implements SoMasterService {

    @Autowired
    private SoMasterMapper soMasterMapper;

    @Autowired
    private ValidatorService validatorService;

    @Autowired
    private SoMasterService soMasterService;

    @Autowired
    private SoDetailService soDetailService;

    @Autowired
    private CaseMasterService caseMasterService;

    @Autowired
    private SoMasterFileService soMasterFileService;

    @Autowired
    private SoDetailFileService soDetailFileService;
    @Autowired
    private RouteTacticService routeTacticService;

    @Autowired
    private BillRecordService billRecordService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private InventoryTransactService inventoryTransactService;
    @Autowired
    private PickTaskService pickTaskService;
    @Autowired
    private SoDetailMapper soDetailMapper;
    @Autowired
    private ErpBackRecordMapper erpBackRecordMapper;
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private ItemInfoMapper itemInfoMapper;
    @Autowired
    private CustomerService customerService;
    @Autowired
    private WaveDetailService waveDetailService;
    @Autowired
    private OutMasterService outMasterService;
    @Autowired
    private PushErpService pushErpService;
    @Autowired
    private CellInfoService cellInfoService;

    @Autowired
    private CodeRuleService codeRuleService;
    @Autowired
    private AsyncService asyncService;

    @Autowired
    private RgProdOutRecordService rgProdOutRecordService;
    @Autowired
    private DataDictDetailService dataDictDetailService;

    @Autowired
    private StrategyErpService strategyErpService;


    @Override
    public List<SoMasterDto> findList(SoMasterCriteria criteria) {
        List<SoMasterDto> list = soMasterMapper.findList(criteria);
        List<DataDictDetail> dataDictDetails = dataDictDetailService.list(new QueryWrapper<DataDictDetail>().eq("data_dict_code", "else"));

        Map<String, DataDictDetail> dataMap = convertMap(dataDictDetails, DataDictDetail::getDictKey);
        for (SoMasterDto soMasterDto : list) {
            DataDictDetail dataDictDetail = dataMap.get(Convert.toStr(soMasterDto.getCategoryId()));
            if (ObjectUtil.isNotEmpty(dataDictDetail)) {
                soMasterDto.setCategoryName(dataDictDetail.getDictValue());
            }
        }
        return list;
    }

    @Override
    public List<SoMasterDto> findByWaveId(Integer id, Integer wareId) {
        return soMasterMapper.findByWaveId(id, wareId);
    }


    @Override
    public SoMasterDto getSeedingByItemCode(String itemCode, Integer wareId, Integer waveMasterId) {
        List<SoMasterDto> list = soMasterMapper.getSeedingByItemCode(itemCode, wareId, waveMasterId);
        if (list.size() > 0) {

            return list.get(0);
        } else {
            return null;
        }
    }


    @Override
    public void deleteByBillNo(String billNo) {
        soMasterMapper.deleteByBillNo(billNo);
    }


    @Override
    public void createSoMaster(SoData soData, CurrentUser currentUser) {
        /**
         *  新建SO单据
         */
        SoMaster soMaster = soData.getSoMaster();


        String billNo = soMaster.getBillNo();
        Integer createUserId = currentUser.getUserId();
        String createUserName = currentUser.getUserName();
        String createTime = DateUtils.getNowDateTimeString();

        if (soData.getBillSource() == 1 || soData.getBillSource() == 3 || soData.getBillSource() == 4) {
            //状态    2-等待审核(初始化)  1-审核通过  0-审核中  -1-审核退回
            Integer state = 1;

            if (soData.getInsertType() == -2) {
                //草稿
                state = 1;
            } else if (soData.getInsertType() == 0) {
                //正式提交
                String billNo1 = soData.getSoMaster().getBillNo();
                //通过草稿提交，则需要先把草稿删掉
                if (billNo1 != null) {
                    soMasterService.deleteByBillNo(billNo1);
                }
                /**
                 * 添加审核流
                 */
                //        -1不通过  0-流转中 1-已通过
                state = caseMasterService.createCase(billNo, 3, currentUser.getUserId(), soMaster.getWareId(), soMaster.getOrganizationId());
            }

            soMaster.setCreateUserId(createUserId);
            soMaster.setCreateUserName(createUserName);
            soMaster.setCreateTime(createTime);
//            soMaster.setBillNo(billNo);
            soMaster.setCaseState(state);
            soMaster.setInsertType(soData.getInsertType());
            soMaster.setBillSource(soData.getBillSource());
            soMaster.setSoStructure(soData.getSoDetails().size());
            soMasterService.save(soMaster);
            List<SoDetail> soDetails = soData.getSoDetails();
            for (int i = 0; i < soDetails.size(); i++) {
                String detailNo = billNo + "-" + (i + 1);
                SoDetail soDetail = soDetails.get(i);
                soDetail.setBillNo(billNo);
                soDetail.setDetailNo(detailNo);
                soDetail.setState(0);
                soDetailService.save(soDetail);
            }
            //拣货分配
            if (soMaster.getSoType() == 41) {
                createPickTask(soDetails, currentUser, soMaster, soData.getFromAreaId());
                soMaster.setState(4);
                soMasterService.updateById(soMaster);
            }

        }
    }


    public void createPickTask(List<SoDetail> soDetails, CurrentUser currentUser, SoMaster soMaster, Integer fromAreaId) {
        List<PickTask> pickTaskList = new ArrayList<>();
        //物料编码集合
        List<Integer> invIds = soDetails.stream().map(item -> item.getInventoryId()).collect(Collectors.toList());
        //Step1.拼接条件(库区，物料)  找到可用容器库存 --这里的库存就是最细的粒度，后续分配的时候也是按容器来分配
        InventoryCriteria inventoryCriteria = new InventoryCriteria();
        inventoryCriteria.setInventoryIds(invIds);
        //查找库存
        List<InventorySelectDto> inventoryDtos = inventoryService.findCanBeOutOfIds(inventoryCriteria);
        Map<Integer, InventorySelectDto> invMap = convertMap(inventoryDtos, InventorySelectDto::getInventoryId);
        for (SoDetail soDetail : soDetails) {
            InventorySelectDto inv = invMap.get(soDetail.getInventoryId());
            //Step2.生成拣货任务
            double remainAllotQty;
            //有预分配数量则取预分配数量，没有则全部分配
            remainAllotQty = soDetail.getOrderQuantity() - soDetail.getAllottedQuantity();
            if (remainAllotQty <= 0) {
                continue;
            }
            //Step2.1新建拣货任务  根据波次明细初始化
            PickTask pickTask = new PickTask(
                    soDetail.getSoDetailId(),
                    soMaster.getSoMasterId(),
                    soMaster.getWareId(),
                    soMaster.getWareName(),
                    soMaster.getOrganizationId(),
                    soMaster.getOrganizationName(),
                    inv.getAreaCode(),
                    inv.getAreaName(),
                    inv.getShelfCode(),
                    inv.getShelfName(),
                    inv.getCellCode(),
                    inv.getCellName(),
                    inv.getItemCode(),
                    inv.getItemName(),
                    inv.getBatchId(),
                    inv.getBatchName(),
                    inv.getBoxCode(),
                    inv.getLpn(),
                    soDetail.getPackDetailId(),
                    soDetail.getPackDescribe(),
                    0.00,
                    0,
                    inv.getInventoryId(),
                    1,
                    soDetail.getImgUrl()
            );
            pickTask.setPickTaskCode(codeRuleService.generateCode(SystemManageConstant.CODE_RULE_PICK));
            //遍历可用库存，分配可用数量 (引申：对于复杂场景，这里可用动态规划的算法)

            //1)可分配数量 大于出库任务明细待分配数量 出库任务明细分配完毕
            pickTask.setPickQuantity(remainAllotQty);
            soDetail.setAllottedQuantity(soDetail.getAllottedQuantity() + pickTask.getPickQuantity());
            //记录波次明细的已分配数量 记录状态为已分配
            InventorySelectDto invDto = invMap.get(inv.getInventoryId());
            invDto.setAllotQuantity(invDto.getAllotQuantity() + pickTask.getPickQuantity());
            invDto.setTransRatio(1.0);
            pickTask.setInventoryId(inv.getInventoryId());
            pickTaskList.add(pickTask);
            //记录状态
            if (ObjectUtil.equal(soDetail.getOrderQuantity(), soDetail.getAllottedQuantity())) {
                soDetail.setState(WareTaskConstant.WAVE_STATE_ALL_ALOT);
            } else {
                soDetail.setState(WareTaskConstant.WAVE_STATE_PICKING);
            }
        }


        List<Inventory> updateInv = new ArrayList<>();
        for (InventorySelectDto inventoryDto : inventoryDtos) {
            Inventory inventory = new Inventory();
            BeanUtils.copyProperties(inventoryDto, inventory);
            updateInv.add(inventory);
        }
        inventoryService.updateBatchById(updateInv);

        //保存生成的拣货任务
        pickTaskService.saveBatch(pickTaskList);
        //更新波次明细状态 和 已分配数量
        //更新波次状态
        soDetailService.updateBatchById(soDetails);
        //冻结任务单数量
    }


    @Override
    public void createFile(String billNo, CurrentUser currentUser) {
        SoMaster soMaster = this.findBy("bill_no", billNo);
        //状态为 ASN完成状态
        Integer fileUserId = currentUser.getUserId();
        String fileUserName = currentUser.getUserName();
        String fileTime = DateUtils.getNowDateTimeString();
        if (soMaster.getState() != 10) {
            throw new ServiceException(CommonCode.SO_FILE_ERROR);
        }
        BillRecord billRecord = new BillRecord();
        billRecord.setBillNo(billNo);
        billRecord.setRecordType(26);//SO归档
        billRecord.setCreateTime(fileTime);
        billRecord.setCreateUserId(fileUserId);
        billRecord.setCreateUserName(fileUserName);
        billRecordService.createBillRecord(billRecord, currentUser);

        SoMasterFile soMasterFile = new SoMasterFile();
        BeanUtils.copyProperties(soMaster, soMasterFile);

        soMasterFile.setFileUserId(fileUserId);
        soMasterFile.setFileUserName(fileUserName);
        soMasterFile.setFileTime(fileTime);
        soMasterFileService.save(soMasterFile);

        List<SoDetail> soDetails = soDetailService.findByBillNo(billNo);

        for (int i = 0; i < soDetails.size(); i++) {
            SoDetail soDetail = soDetails.get(i);
            SoDetailFile soDetailFile = new SoDetailFile();
            BeanUtils.copyProperties(soDetail, soDetailFile);
            soDetailFileService.save(soDetailFile);
        }
        soMasterService.deleteByBillNo(billNo);
        BillRecord billRecord1 = billRecordService.findByBillNoAndType(billNo, 26);//SO归档
        billRecord1.setModifyUserId(fileUserId);
        billRecord1.setModifyUserName(fileUserName);
        billRecord1.setModifyTime(DateUtils.getNowDateTimeString());
        billRecordService.updateById(billRecord1);
    }

    @Override
    public SoMaster findBy(String fileName, String value) {
        QueryWrapper<SoMaster> qw = new QueryWrapper<>();
        return this.getOne(qw.eq(fileName, value));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> sendOut(SoMaster soMaster, CurrentUser currentUser, String pickIds, String cellCode) {
        Map<String, String> returnMap = new HashMap<>();
        returnMap.put("msg", "提交成功");
        List<OutDetail> outDetails = new ArrayList<>();
        //Step1.生成库存事务
//        List<PickTask> pickTasks = pickTaskService.list(new QueryWrapper<PickTask>().eq("so_master_id", soMaster.getSoMasterId()));

        List<PickTask> pickTasks = pickTaskService.listByIds(Arrays.asList(pickIds.split(",")));
        for (PickTask pickTask : pickTasks) {
            toStockRequest(pickTask, currentUser);
        }
        //Step3.回写单据状态

        setSomasterState(soMaster);
//        soMaster.setState(WareTaskConstant.SO_STATE_OUTED);
        soMaster.setOutTime(DateUtils.getNowDateTimeString());
        soMaster.setOutUserId(currentUser.getUserId());
        soMaster.setOutUserName(currentUser.getUserName());

        List<SoDetail> soDetails = soDetailService.findByBillNo(soMaster.getBillNo());
        Double sumQcQty = 0.00;

        for (PickTask pickTask : pickTasks) {
            OutDetail outDetail = new OutDetail();
            SoDetail soDetail = soDetailService.getById(pickTask.getSoDetailId());
            if (ObjectUtil.isEmpty(soDetail)) {
                continue;
            }
            soDetail.setDeliveryQuantity(soDetail.getOrderQuantity());
            soDetail.setState(WareTaskConstant.SO_DETAIL_STATE_ALL_SEND);
            BeanUtils.copyProperties(soDetail, outDetail);
            outDetail.setDeliveryQuantity(pickTask.getPickQuantity()); //数量
//            System.out.println(allotInv.getInventoryId());
            outDetail.setBoxCode(pickTask.getBoxCode());
            outDetail.setCellCode(pickTask.getCellCode());
//            outDetail.setBatchName(pickTask.getBatchName());
            List<AreaInfoDto> byCode = areaInfoService.findByCode(pickTask.getAreaCode());
            Inventory allotInv = inventoryService.getById(pickTask.getInventoryId());
            outDetail.setErpAreaId(allotInv.getErpAreaId());
            outDetail.setBatchName(allotInv.getBatchName());
            outDetails.add(outDetail);

//            if (ObjectUtil.isEmpty(allotInv)) {
//                continue;
//            }


        }


        soMaster.setQcQty(soMaster.getSoQty() + sumQcQty);
        soDetailService.updateBatchById(soDetails);
        soMasterService.updateById(soMaster);

        for (PickTask pickTask : pickTasks) {
            pickTask.setSeededQuantity(pickTask.getPickQuantity());
            pickTask.setState(WareTaskConstant.PICK_STATE_OUTED);
        }
        pickTaskService.updateBatchById(pickTasks);
        return asyncService.asyncReview(soMaster, cellCode, outDetails, currentUser, pickIds);
    }

    @Autowired
    private AreaInfoService areaInfoService;

    public void setSomasterState(SoMaster soMaster) {
        String billNo = soMaster.getBillNo();
        List<SoDetail> soDetail = soDetailService.list(new QueryWrapper<SoDetail>().in("bill_no", billNo));
        double orderQty = soDetail.stream().mapToDouble(SoDetail::getOrderQuantity).sum();
        double senQty = soDetail.stream().mapToDouble(SoDetail::getDeliveryQuantity).sum();


        if (orderQty < senQty) {
            soMaster.setState(WareTaskConstant.SO_STATE_PART_OUT);
        } else {
            soMaster.setState(WareTaskConstant.SO_STATE_OUTED);
            ;
        }

    }

    public void allot(String pickIds, String cellCode) {
        List<String> pickId = Arrays.asList(pickIds.split(","));
        List<PickTask> pickTasks = pickTaskService.listByIds(pickId);
        Set<Integer> integers = pickTasks.stream().map(PickTask::getInventoryId).collect(Collectors.toSet());
        List<Inventory> inventories = inventoryService.listByIds(integers);
        Map<Integer, List<Inventory>> invMap = inventories.stream().collect(Collectors.groupingBy(Inventory::getInventoryId));
        for (PickTask pickTask : pickTasks) {
            List<Inventory> inventoryList = invMap.get(pickTask.getInventoryId());
            inventoryList.forEach(oldInventory -> {
                Inventory inventory = new Inventory();
                BeanUtils.copyProperties(oldInventory, inventory);
                Integer erpAreaId = cellInfoService.findbyCellCode(cellCode);
                //分配数量
                oldInventory.setAllotQuantity(oldInventory.getAllotQuantity() - pickTask.getPickQuantity());
                //库存数量
                oldInventory.setQuantity(oldInventory.getQuantity() - pickTask.getPickQuantity());
                inventory.setInventoryId(null);
                inventory.setBoxCode(codeRuleService.generateCodeByRedis("CT"));
                inventory.setErpAreaId(erpAreaId);
                inventory.setQuantity(pickTask.getPickQuantity());
                inventory.setAllotQuantity(0.00);
                inventory.setCellCode(cellCode);
                inventoryService.save(inventory);
            });

        }

    }


    private InventoryTransact toStockRequest(PickTask pickTask, CurrentUser currentUser) {
        InventoryTransact inventoryTransact = new InventoryTransact();
        //Step1.准备数据
        //仓库
        inventoryTransact.setWareId(pickTask.getWareId());
        inventoryTransact.setWareName(pickTask.getWareName());
        //货主
        inventoryTransact.setToOrganizationId(pickTask.getOrganizationId());
        inventoryTransact.setToOrganizationName(pickTask.getOrganizationName());
        //库位
        inventoryTransact.setFromCellCode(pickTask.getCellCode());
        //容器
        inventoryTransact.setFromBoxCode(pickTask.getBoxCode());
        //物料
        inventoryTransact.setItemCode(pickTask.getItemCode());
        inventoryTransact.setItemName(pickTask.getItemName());
        inventoryTransact.setImgUrl(pickTask.getImgUrl());
        //批次
        inventoryTransact.setFromBatchId(pickTask.getBatchId());
        inventoryTransact.setFromBatchName(pickTask.getBatchName());
        //数量
        inventoryTransact.setFromQuantity(pickTask.getPickQuantity());
        //包装 转换率
        inventoryTransact.setFromPackDetailId(pickTask.getPackDetailId());
        inventoryTransact.setFromPackDescribe(pickTask.getPackDescribe());
        //创建人 时间
        inventoryTransact.setCreateUserId(currentUser.getUserId());
        inventoryTransact.setCreateUserName(currentUser.getUserName());
        inventoryTransact.setCreateTime(DateUtil.now());
        //事务类型
        inventoryTransact.setTransactType(InventoryConstant.INVENTORY_TYPE_OUT);
        //来源单据号
        inventoryTransact.setBillNo(pickTask.getPickTaskCode());

        //Step2.保存，返回
        inventoryTransactService.save(inventoryTransact);
        return inventoryTransact;
    }

    @Override
    public List<SoMaster> findSoGroupInfo(SoMasterCriteria criteria) {
        return soMasterMapper.findSoGroupInfo(criteria);
    }

    @Override
    public List<SoMaster> findSoByWave(SoMasterCriteria criteria) {
        return soMasterMapper.findSoByWave(criteria);
    }

    @Override
    public Integer findCountByWaveIdAndState(Integer waveMasterId, Integer state) {
        return soMasterMapper.findCountByWaveIdAndState(waveMasterId, state);
    }


    @Override
    public List<SoMaster> findCanTongBu() {
        return soMasterMapper.findCanTongBu();
    }

    @Override
//    public void setCarriersWithRouteTactic(Integer organizationId, Integer wareId) {
    public void setCarriersWithRouteTactic() {
        SoMasterCriteria soMasterCriteria = new SoMasterCriteria();
//        soMasterCriteria.setOrganizationId(organizationId);
//        soMasterCriteria.setWareId(wareId);
        List<SoMasterDto> soMasters = soMasterMapper.findThatNoCarrier(soMasterCriteria);
        RouteTacticCriteria criteria = new RouteTacticCriteria();
//        criteria.setOrganizationId(organizationId);
//        criteria.setWareId(wareId);
        criteria.setState(1);
        List<RouteTactic> routeTactics = routeTacticService.findList(criteria);
        if (routeTactics.size() == 0) {
            throw new ServiceException(CommonCode.NO_ROUTE_TACTIC);
        }

        for (SoMasterDto soMaster : soMasters) {
            Double weight = soMaster.getWeight();
            Double size = soMaster.getSize();
            tacticLoop:
            for (RouteTactic routeTactic : routeTactics) {
                Double maxWeight = routeTactic.getMaxWeight();
                Double minWeight = routeTactic.getMinWeight();
                Double maxSize = routeTactic.getMaxSize();
                Double minSize = routeTactic.getMinSize();
                if (weight > minWeight && weight < maxWeight && size > minSize && size < maxSize) {
                    soMaster.setCarrierId(routeTactic.getCarrierId());
                    soMaster.setCarrierName(routeTactic.getCarrierName());
                    soMasterService.updateById(soMaster);
                    break tacticLoop;
                }
            }
        }
    }

    @Override
    public List<PdaSearchSoData> pdaSearchSo(String trackCode) {
        return soMasterMapper.pdaSearchSo(trackCode);
    }

    @Override
    public SoMasterYdyp getYdyp(String itemCode, Integer wareId, Integer waveId) {
        return soMasterMapper.getYdyp(itemCode, wareId, waveId);
    }

    @Override
    public SoMasterYdyp getYdyp2(String itemCode, Integer wareId, Integer waveId) {
        return soMasterMapper.getYdyp2(itemCode, wareId, waveId);
    }


    @Autowired
    private WareInfoService wareInfoService;
    @Autowired
    private ItemInfoService itemInfoService;
    @Autowired
    private OrganizationService organizationService;

    @Override
    public void createSO(CreateSo createSo, CurrentUser currentUser) {
        SoMaster soMaster = soMaster = this.findBy("bill_no", createSo.getBillNo());
        if (soMaster != null) {
            throw new ServiceException(CommonCode.BILL_NO, "");
        }
        soMaster = new SoMaster();
        if (createSo.getWareCode() == null) {
            throw new ServiceException(CommonCode.WARE_NULL, "");
        }
        if (createSo.getOrgCode() == null) {
            throw new ServiceException(CommonCode.ORG_NULL, "");
        }

        String billNo = createSo.getBillNo();
        Integer createUserId = currentUser.getUserId();
        String createUserName = currentUser.getUserName();
        String createTime = DateUtils.getNowDateTimeString();
        String wareCode = createSo.getWareCode();
        String orgCode = createSo.getOrgCode();
        WareInfo wareInfo = wareInfoService.getOneByField("ware_code", wareCode);
        Organization organization = organizationService.findBy("organizationCode", orgCode);

        if (createSo.getOrderTime() == null || createSo.getOrderTime().equals("")) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "下单时间不得为空");
        }

        if (wareInfo == null) {
            throw new ServiceException(CommonCode.WARE_NULL, "");
        }
        if (organization == null) {
            throw new ServiceException(CommonCode.ORG_NULL, "");
        }
        Integer state = 2;
        // state = caseMasterService.createCase(billNo, 2, currentUser.getUserId(), wareInfo.getWareId(),organization.getOrganizationId());

        soMaster.setState(state);
        soMaster.setBillNo(billNo);
        soMaster.setCreateTime(createTime);
        soMaster.setCreateUserId(createUserId);
        soMaster.setCreateUserName(createUserName);
        soMaster.setWareId(wareInfo.getWareId());
        soMaster.setWareName(wareInfo.getWareName());
        soMaster.setWareId(wareInfo.getWareId());
        soMaster.setWareCode(wareInfo.getWareCode());
        soMaster.setOrganizationCode(organization.getOrganizationCode());
        soMaster.setOrganizationName(organization.getOrganizationName());
        soMaster.setOrganizationId(organization.getOrganizationId());
        soMaster.setAllotBillNo(createSo.getBillNo());
        soMaster.setShipCode(createSo.getShipCode());
        soMaster.setShipBillCode(createSo.getShipBillCode());
        soMaster.setExpressBillUrl(createSo.getExpressBillUrl());
        soMaster.setInsertType(4);
        soMaster.setOrderTime(createSo.getOrderTime());

        CreateSoShippingAddress shippingAddress = createSo.getShippingAddress();
        soMaster.setShipLinkMan(shippingAddress.getLinkMan());
        soMaster.setShipLinkPhone(shippingAddress.getLinkPhone());
        soMaster.setShipCity(shippingAddress.getCity());
        soMaster.setShipCountry(shippingAddress.getCountry());
        soMaster.setShipProvince(shippingAddress.getProvince());
        soMaster.setShipArea(shippingAddress.getArea());
        soMaster.setShipDetailAddress(shippingAddress.getDetailAddress());

        CreateSoDeliveryAddress deliveryAddress = createSo.getDeliveryAddress();
        soMaster.setLinkMan(deliveryAddress.getLinkMan());
        soMaster.setLinkPhone(deliveryAddress.getLinkPhone());
        soMaster.setProvince(deliveryAddress.getProvince());
        soMaster.setCity(deliveryAddress.getCity());
        soMaster.setCountry(deliveryAddress.getCountry());
        soMaster.setArea(deliveryAddress.getArea());
        soMaster.setDetailAddress(deliveryAddress.getDetailAddress());
        soMaster.setCountry(deliveryAddress.getCountry());


        soMaster.setLastMileDestination(createSo.getLastMileDestination());
        soMaster.setLastMileLineCode(createSo.getLastMileLineCode());
        soMaster.setLastMileSortingCode(createSo.getLastMileSortingCode());
        soMaster.setSoUdfHs1(createSo.getExt1());
        soMaster.setSoUdfHs2(createSo.getExt2());
        soMaster.setSoUdfHs3(createSo.getExt3());
        soMaster.setSoStructure(createSo.getSoSkuDetails().size());
        soMaster.setTotalPrice(createSo.getCodValue());
        soMaster.setTradeNo(createSo.getTradeNo());
        soMaster.setShop(createSo.getShop());
        soMasterService.save(soMaster);


        List<CreateSoSkuDetail> asnskuDetails = createSo.getSoSkuDetails();
        for (int i = 0; i < asnskuDetails.size(); i++) {
            CreateSoSkuDetail createSoSkuDetail = asnskuDetails.get(i);

            SoDetail soDetail = new SoDetail();
            soDetail.setBillNo(soMaster.getBillNo());
            soDetail.setDetailNo(soMaster.getBillNo() + (i + 1));
            soDetail.setItemCode(createSoSkuDetail.getSkuCode());

            if (createSoSkuDetail.getSkuCode() == null || createSoSkuDetail.getSkuCode().trim().equals("")) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "SKU无效");
            }
            ItemInfo itemInfo = itemInfoService.findBy("item_code", createSoSkuDetail.getSkuCode());
            if (itemInfo == null) {
                itemInfo = new ItemInfo();
                itemInfo.setImgUrl(createSoSkuDetail.getImgUrl());
                itemInfo.setItemCode(createSoSkuDetail.getSkuCode());
                itemInfo.setItemName(createSoSkuDetail.getSkuName());
                itemInfo.setPackCode("sys_pack");
                itemInfoService.save(itemInfo);
            }
            soDetail.setItemName(itemInfo.getItemName());
            soDetail.setSpec(itemInfo.getSpec());
            soDetail.setModel(itemInfo.getModel());
            soDetail.setImgUrl(itemInfo.getImgUrl());
            soDetail.setPackDetailId(166);
            soDetail.setTransRatio(1.0);
            soDetail.setPackDescribe("each");
            soDetail.setOrderQuantity(createSoSkuDetail.getQuantity());
            soDetailService.save(soDetail);
        }
    }

    @Override
    public Integer getMaxPriority() {
        return soMasterMapper.getMaxPriority();
    }

    @Override
    public void updatePriority(Integer soMasterId, Integer priority) {
        soMasterMapper.updatePriority(soMasterId, priority);
    }


    //去重出库表
    public List<BillOutBO> filterBillOut(List<BillOutBO> billOutBOS, Set<String> billNo, List<Integer> notBillNums) {

        //不包含的单据类型

        return billOutBOS.stream().filter(item -> !billNo.contains(item.getBillNo())
                && !notBillNums.contains(item.getBillTypeId())

        ).collect(Collectors.toList());
    }


    //去重出库详情表
    public List<BillOutDetailBO> filterDetaiBo(List<BillOutDetailBO> billOutDetailBOS, Set<String> billNo, List<Integer> notBillNums) {
        return billOutDetailBOS.stream().filter(item -> !billNo.contains(item.getBillNo()) && !notBillNums.contains(item.getBillType())).collect(Collectors.toList());
    }

    public List<BillOutDetailBO> insertBillNo(BillOutBO billOutBO) {
        List<BillOutDetailBO> billOutDetail = billOutBO.getDetails();
        return billOutDetail.stream().map(
                item -> {
                    item.setSupplierName(billOutBO.getSupplierName());
                    item.setBillNo(billOutBO.getBillNo());
                    item.setOrderBillNo(billOutBO.getOrderBillNo());
                    item.setSourceBillId(billOutBO.getId());
                    item.setBillType(billOutBO.getBillTypeId());

                    return item;
                }
        ).collect(Collectors.toList());
    }

//
//    public List<BillOutDetailBO> getAllBillOut(List<BillOutDetailBO> list) {
//
//    }

    public Double sumSoQty(List<BillOutDetailBO> list, String billNo) {
        return list.stream().filter(item -> item.getBillNo().equals(billNo)).mapToDouble(BillOutDetailBO::getQty).sum();
    }

    public Double sumQcQty(List<BillOutDetailBO> list, String billNo) {
        return list.stream().filter(item -> item.getBillNo().equals(billNo)).mapToDouble(BillOutDetailBO::getQcQty).sum();
    }

//    @Override
//    public String saveBillOutInfo(String date) {
//        Integer wareId = 285;
//        List<WareInfo> wareInfoList = wareInfoService.list();
//        Map<Integer, List<WareInfo>> wareMap = wareInfoList.stream().collect(Collectors.groupingBy(WareInfo::getWareId));
//        List<Integer> notBillNums = Arrays.asList(82, 251300022, 251300022, 251300058, 200000013);
//
//        try {
//            //请求token
//            String token = pushErpService.getToken();
//            if (token != null) {
//                Map<String, String> map1 = new HashMap<>();
//                Calendar calendar = Calendar.getInstance();
//                calendar.setTime(new Date());
//                map1.put("dateFrom", date);
//                CloseableHttpClient client = HttpClients.createDefault();
//                URIBuilder uriBuilder = new URIBuilder("https://syecrg.sieyuan.com:44398/api/Epichust/GetAllIMOutSourceBills");
//                HttpPost post = new HttpPost(uriBuilder.build());
//                StringEntity myEntity = new StringEntity(JSON.toJSONString(map1), "UTF-8");// 构造请求数据
//                post.setHeader("Content-Type", "application/json");
//                post.addHeader("Authorization", "Bearer " + token);
//                post.setEntity(myEntity);// 设置请求体
//                String responseContent = null; // 响应内容
//                CloseableHttpResponse response = null;
//                try {
//                    response = client.execute(post);
//                    HttpEntity entity = response.getEntity();
//                    if (response.getStatusLine().getStatusCode() == 200) {
//                        String content = EntityUtils.toString(entity, "UTF-8");
//                        //订单数量
//                        List<BillOutBO> po = (List<BillOutBO>) JSON
//                                .parseArray(content, BillOutBO.class);
//                        //获取所有详情信息
//                        List<SoMaster> soMasters = new ArrayList<>();
//                        List<SoDetail> soDetailList = new ArrayList<>();
//                        List<BillOutDetailBO> billOutDetailBOS = new ArrayList<>();
//                        po.stream().map(item -> {
//                            item.setDetails(this.insertBillNo(item));
//                            billOutDetailBOS.addAll(item.getDetails());
//                            return item;
//                        }).collect(Collectors.toList());
//
//
//                        //入库单据
//                        List<BillOutDetailBO> billOutDetailBOList = billOutDetailBOS.stream().filter(item -> notBillNums.contains(item.getBillType())).collect(Collectors.toList());
//
//                        //单号去重
//
//
//                        Set<String> oldBillNos = po.stream().map(BillOutBO::getBillNo).collect(Collectors.toSet());
//
//                        //获取订单中所有的数据
//                        List<SoMaster> soMasterList = soMasterService.list(new QueryWrapper<SoMaster>().in("bill_no", oldBillNos));
//                        Set<String> newBillNos = soMasterList.stream().map(SoMaster::getBillNo).collect(Collectors.toSet());
//                        //不包含单号的数据
//                        List<BillOutBO> billOutBOS = this.filterBillOut(po, newBillNos, notBillNums);
//                        List<BillOutDetailBO> billOutDetailBOS1 = filterDetaiBo(billOutDetailBOS, newBillNos, notBillNums);
//
//
//                        if (ObjectUtil.isEmpty(billOutBOS) && ObjectUtil.isEmpty(billOutDetailBOS1)) {
//                            return null;
//                        }
//                        Set<String> itemNumbers = billOutDetailBOS1.stream().map(BillOutDetailBO::getItemNumber).collect(Collectors.toSet());
//                        //获取所有物料
//                        List<ItemInfo> itemInfoList = itemInfoService.list(new QueryWrapper<ItemInfo>().in("item_code", itemNumbers));
//                        Map<String, List<BillOutDetailBO>> detailMap = billOutDetailBOS1.stream().filter(item->billOutDetailBOS1.contains(item.getBillNo())).collect(Collectors.groupingBy(BillOutDetailBO::getBillNo));
//                        //红蓝字对冲如果有红字
//                        List<BillOutDetailBO> merge = merge(detailMap);
//                        //新增详情
//                        Set<String> detailBillNo = new HashSet<>();
//                        for (BillOutDetailBO billOutDetailBO : merge) {
//
////                            QueryWrapper<ItemInfo> ct = Wrappers.query();
////                            ItemInfo itemInfo = itemInfoMapper.selectOne(ct.eq("item_code", billOutDetailBO.getItemNumber()));
//                            ItemInfo itemInfo = itemInfoList.stream().filter(item -> item.getItemCode().equals(billOutDetailBO.getItemNumber())).collect(Collectors.toList()).get(0);
//                            if (itemInfo.getPickTacticCode() != "标准件" && itemInfo.getPickTacticCode() != "标准件-MRP物料" && itemInfo.getPickTacticCode() != "辅料-MRP物料" && itemInfo.getPickTacticCode() != "辅料") {
//                                detailBillNo.add(billOutDetailBO.getBillNo());
//                                SoDetail soDetail = new SoDetail();
//
//                                soDetail.setBillNo(billOutDetailBO.getBillNo());
//                                soDetail.setBomSplit(billOutDetailBO.getRowIndex());//行号
//                                soDetail.setAllotPackDetailId(billOutDetailBO.getItemId());//物料ID
//                                soDetail.setItemCode(billOutDetailBO.getItemNumber());//物料编码
//                                soDetail.setItemName(billOutDetailBO.getItemName());//物料名称
//                                soDetail.setSpec(billOutDetailBO.getItemModel());//规格型号
//                                soDetail.setPickPackDetailId(billOutDetailBO.getAuxPropClassId());//辅助属性类别ID
//                                soDetail.setDeliveryPackDetailId(billOutDetailBO.getAuxPropId());//辅助属性ID
//                                soDetail.setModel(billOutDetailBO.getAuxPropName());//辅助属性
//                                //批次管理
//                                soDetail.setPackDescribe(billOutDetailBO.getBatchManager() == null || billOutDetailBO.getBatchManager() == false ? "0" : "1");
//                                soDetail.setDetailNo(billOutDetailBO.getBatchNo());//批号
//                                soDetail.setPackDetailId(billOutDetailBO.getUnitId());//基本单位ID
//                                soDetail.setSoUdfDs2(billOutDetailBO.getUnitName());//单位
//                                soDetail.setOrderQuantity(billOutDetailBO.getQty());//基本单位数量
//                                soDetail.setPickQuantity(billOutDetailBO.getQcQty());
////                                soDetail.setAllotPackDescribe(billOutDetailBO.getPlanModeId().toString());//计划模式ID
//                                soDetail.setSoUdfDs3(billOutDetailBO.getMtoNo());//计划跟踪号
//                                soDetail.setMemo(billOutDetailBO.getRemark());//备注
//                                soDetail.setPickPackDescribe(billOutDetailBO.getTargetBillTypeId().toString());//目标单据类型ID
//                                //目标单据红蓝字
//                                soDetail.setRob(billOutDetailBO.getTargetBillROB());
//                                soDetail.setAllotPackDescribe(billOutDetailBO.getShelfLifeDays().toString());
//                                soDetail.setDeliveryPackDescribe(billOutDetailBO.getShelfLifeManager() == null || billOutDetailBO.getShelfLifeManager() == false ? "0" : "1");
//                                soDetail.setAllotDetailNo(billOutDetailBO.getProductionDate());
//                                soDetail.setTransRatio(1.00);
//                                soDetailList.add(soDetail);
//                            }
//
//                        }
//                        //新增任务
//                        for (BillOutBO billOutBO : billOutBOS) {
//                            if (!detailBillNo.contains(billOutBO.getBillNo())) {
//                                continue;
//                            }
//                            ;
//                            SoMaster soMaster = new SoMaster();
//                            soMaster.setCreateTime(DateUtils.getNowDateTimeString());
//                            soMaster.setOrganizationId(86);//货主id
//                            soMaster.setWareId(wareId);//仓库id
//                            soMaster.setWareCode(wareMap.get(wareId).get(0).getWareCode());
//                            soMaster.setWareName(wareMap.get(wareId).get(0).getWareName());
//                            soMaster.setSupplierId(billOutBO.getSupplierId());//供应商id
//                            soMaster.setSupplierName(billOutBO.getSupplierName()); // 供应商名称
//                            soMaster.setOrderBillNo(billOutBO.getOrderBillNo()); //订单号
//                            soMaster.setBeforeNum(billOutBO.getId());
//
//                            soMaster.setSoType(detailMap.get(billOutBO.getBillNo()).iterator().next().getTargetBillTypeId());
//                            //单据数量
//                            soMaster.setSoQty(this.sumSoQty(billOutDetailBOS1, billOutBO.getBillNo()));
//                            //出库数量
//                            soMaster.setQcQty(this.sumQcQty(billOutDetailBOS1, billOutBO.getBillNo()));
////                            soMaster.setCreateUserName(billOutBO.getBillTypeId().toString()); //单据类型id
//                            soMaster.setBillType(billOutBO.getBillTypeId()); //单据类型id
////                            soMaster.setWareCode(billOutBO.getBillTypeName());//单据类型名称
//                            soMaster.setSoTypeName(billOutBO.getBillTypeName());//单据类型名称
//
//                            soMaster.setTradeNo(billOutBO.getAgreementNo());  //履约号
//                            soMaster.setBillNo(billOutBO.getBillNo());//单据编号
//                            soMaster.setShipCode(billOutBO.getBillDate());//单据日期
//                            //工业单据状态 0 - 草稿 1 - 已审核，未关联 2 - 已审批，部分关联 3 - 已审批，全部关联 生产任务单据状态 0 - 计划 5 - 确认 1 - 下达 3 - 结案 BOS单据状态 2 - 未审核 4 - 审核中 16 - 已审核
//                            soMaster.setCarrierId(billOutBO.getBillStatus());//工业单据状态
//                            soMaster.setIsClose(billOutBO.getBillClosed() == null || billOutBO.getBillClosed() == false ? 0 : 1);//关闭状态
//                            soMaster.setOrganizationId(-1);
//                            soMaster.setOrganizationName("自有");
//                            soMaster.setOrganizationCode("SYS_MINE");
//
//                            soMaster.setDeptId(billOutBO.getDeptId());//部门ID
//                            soMaster.setDeptName(billOutBO.getDeptName());//部门名称
//                            soMaster.setMemo(billOutBO.getRemark());//备注
//                            soMaster.setExpectTimeFm(billOutBO.getPlanStartDate());//计划开工日期
//                            soMaster.setCustomerId(billOutBO.getCustomerId());//客户ID
//                            soMaster.setCustomerName(billOutBO.getCustomerName());//客户名称
//                            //新增
//                            soMasters.add(soMaster);
//                        }
//
//                        //批量新增
//                        this.different(billOutBOS);
//                        //合并物料编码一样的单据,物料编码一样的数量++
////                        List<SoDetail> soDetails = this.merge(soDetailList);
//                        //批量新增 soMaster
//                        soMasterService.saveBatch(soMasters);
//                        //批量新增 详情
//                        soDetailService.saveBatch(soDetailList);
//                        //执行拣货任务
////                        pickTaskService.createPickTask(null);
//
//
//                    }
//                } catch (Exception e) {
//                    e.printStackTrace();
//                } finally {
//                    try {
//                        if (response != null)
//                            response.close();
//
//                    } catch (IOException e) {
//                        e.printStackTrace();
//                    } finally {
//                        try {
//                            if (client != null)
//                                client.close();
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }
//                    }
//                }
//            }
//
//        } catch (Exception e) {
//            e.printStackTrace();
//            return null;
//        }
//
//        return null;
//    }


    //红蓝字对冲
    public List<BillOutDetailBO> merge(Map<String, List<BillOutDetailBO>> soDetailMap) {
        List<BillOutDetailBO> billOutDetailBOList = new ArrayList<>();
        soDetailMap.forEach((key, val) -> {
            //过滤一遍蓝字标准件                                    红蓝字为ture
            List<BillOutDetailBO> collect = val.stream().filter(BillOutDetailBO::getTargetBillROB).collect(Collectors.toList());
            Set<String> collect2 = collect.stream().map(item -> item.getItemNumber()).collect(Collectors.toSet());
            System.out.println(collect2);
            List<BillOutDetailBO> collectTwo = val.stream().filter(item -> item.getTargetBillROB() == false).collect(Collectors.toList());
            Set<String> collect1 = collectTwo.stream().map(item -> item.getItemNumber()).collect(Collectors.toSet());
            System.out.println(collect1);
            //遍历详情数据
            for (BillOutDetailBO billOutDetailBO : collect) {
                if (billOutDetailBO.getItemNumber().equals("08.10.0033")) {
                    System.out.println("11111");
                }
                //过滤跟根据物料编码遍历红字
                List<BillOutDetailBO> billOutDetailFalse = val.stream().filter(item -> !item.getTargetBillROB()
                        && item.getItemNumber().equals(billOutDetailBO.getItemNumber())
                        && ObjectUtil.isNotEmpty(item)).collect(Collectors.toList());
                //for循环红字
                for (BillOutDetailBO outDetailBO : billOutDetailFalse) {
                    //如果篮字数量大于红字数量
                    if (billOutDetailBO.getOriginQty() - outDetailBO.getOriginQty() >= 0) {
                        //修改对冲修改红字数量
                        Double qty = billOutDetailBO.getOriginQty() - outDetailBO.getOriginQty();
                        billOutDetailBO.setOriginQty(qty);
                        billOutDetailBO.setQty(billOutDetailBO.getQty() - outDetailBO.getOriginQty());
                        outDetailBO.setOriginQty(0.00);
                        //重写hashCode 根据id删除
//                        billOutDetailFalse.remove(outDetailBO);
                        val.remove(outDetailBO);
                    } else if (billOutDetailBO.getOriginQty() < outDetailBO.getOriginQty()) {
                        outDetailBO.setOriginQty(outDetailBO.getOriginQty() - billOutDetailBO.getOriginQty());
                        outDetailBO.setQcQty(outDetailBO.getOriginQty() - billOutDetailBO.getOriginQty());
                        //不足待分配
                        billOutDetailBO.setOriginQty(0.00);
                        //数量制空抵消
                    }
                }
                billOutDetailBOList.add(billOutDetailBO);
            }
        });
        return billOutDetailBOList.stream().filter(item -> item.getOriginQty() != 0).collect(Collectors.toList());
    }


    public void different(List<BillOutBO> list) {

        Set<Integer> newCollect = list.stream().map(BillOutBO::getCustomerId).collect(Collectors.toSet());
        Set<Integer> oldCustomers = customerMapper.selectBatchIds(newCollect).stream().map(Customer::getCustomerId).collect(Collectors.toSet());

        Set<Integer> collect = newCollect.stream().filter(item -> !oldCustomers.contains(item)).collect(Collectors.toSet());
        List<BillOutBO> newList = list.stream().filter(item -> collect.contains(item.getCustomerId()) && item.getCustomerId() != 0).collect(Collectors.toList());

        Set<Customer> customerList = new HashSet<>();
        for (BillOutBO billOutBO : newList) {
            Customer customer = new Customer();
            customer.setCustomerId(billOutBO.getCustomerId());
            customer.setCustomerName(billOutBO.getCustomerName());
            customerList.add(customer);
        }
        customerService.saveBatch(customerList);
    }


    @Override
    public void createSoMaster2(SoData soData, CurrentUser currentUser) {
        /**
         *  新建SO单据
         */
        SoMaster soMaster = soData.getSoMaster();
        String tableName = "so_master";
        Integer nextId = validatorService.getNextId(tableName);

        String billNo = "SO" + "-" + nextId;
        Integer createUserId = currentUser.getUserId();
        String createUserName = currentUser.getUserName();
        String createTime = DateUtils.getNowDateTimeString();

        if (soData.getBillSource() == 1 || soData.getBillSource() == 3 || soData.getBillSource() == 4) {
            //状态    2-等待审核(初始化)  1-审核通过  0-审核中  -1-审核退回
            Integer state = 1;

            if (soData.getInsertType() == -2) {
                //草稿
                state = 1;
            } else if (soData.getInsertType() == 0) {
                //正式提交
                String billNo1 = soData.getSoMaster().getBillNo();
                //通过草稿提交，则需要先把草稿删掉
                if (billNo1 != null) {
                    soMasterService.deleteByBillNo(billNo1);
                }
                /**
                 * 添加审核流
                 */
                //        -1不通过  0-流转中 1-已通过
                state = caseMasterService.createCase(billNo, 3, currentUser.getUserId(), soMaster.getWareId(), soMaster.getOrganizationId());
            }

            soMaster.setCreateUserId(createUserId);
            soMaster.setCreateUserName(createUserName);
            soMaster.setCreateTime(createTime);
            soMaster.setBillNo(billNo);
            soMaster.setCaseState(state);
            soMaster.setInsertType(soData.getInsertType());
            soMaster.setBillSource(soData.getBillSource());
            soMaster.setSoStructure(soData.getSoDetails().size());
            soMaster.setSoUdfHs1("1");//标记先发配件出库单据
            soMasterService.save(soMaster);


            List<SoDetail> soDetails = soData.getSoDetails();
            for (int i = 0; i < soDetails.size(); i++) {
                String detailNo = billNo + "-" + (i + 1);
                SoDetail soDetail = soDetails.get(i);
                soDetail.setBillNo(billNo);
                soDetail.setDetailNo(detailNo);
                soDetail.setState(0);
                soDetailService.save(soDetail);
            }
        }
    }

    @Override
    public List<SoMasterDto> findList2(SoMasterCriteria criteria) {
        return soMasterMapper.findList2(criteria);
    }

    @Override
    public void createSoMaster3(SoData soData, CurrentUser currentUser) {
        /**
         *  新建SO单据
         */
        SoMaster soMaster = soData.getSoMaster();
        String tableName = "so_master";
        Integer nextId = validatorService.getNextId(tableName);

        String billNo = "SO" + "-" + nextId;
        Integer createUserId = currentUser.getUserId();
        String createUserName = currentUser.getUserName();
        String createTime = DateUtils.getNowDateTimeString();

        if (soData.getBillSource() == 1 || soData.getBillSource() == 3 || soData.getBillSource() == 4) {
            //状态    2-等待审核(初始化)  1-审核通过  0-审核中  -1-审核退回
            Integer state = 1;

            if (soData.getInsertType() == -2) {
                //草稿
                state = 1;
            } else if (soData.getInsertType() == 0) {
                //正式提交
                String billNo1 = soData.getSoMaster().getBillNo();
                //通过草稿提交，则需要先把草稿删掉
                if (billNo1 != null) {
                    soMasterService.deleteByBillNo(billNo1);
                }
                /**
                 * 添加审核流
                 */
                //        -1不通过  0-流转中 1-已通过
                state = caseMasterService.createCase(billNo, 3, currentUser.getUserId(), soMaster.getWareId(), soMaster.getOrganizationId());
            }

            soMaster.setCreateUserId(createUserId);
            soMaster.setCreateUserName(createUserName);
            soMaster.setCreateTime(createTime);
            soMaster.setBillNo(billNo);
            soMaster.setCaseState(state);
            soMaster.setInsertType(soData.getInsertType());
            soMaster.setBillSource(soData.getBillSource());
            soMaster.setSoStructure(soData.getSoDetails().size());
            soMaster.setSoUdfHs1("2");//标记先发配件出库单据
            soMasterService.save(soMaster);


            List<SoDetail> soDetails = soData.getSoDetails();
            for (int i = 0; i < soDetails.size(); i++) {
                String detailNo = billNo + "-" + (i + 1);
                SoDetail soDetail = soDetails.get(i);
                soDetail.setBillNo(billNo);
                soDetail.setDetailNo(detailNo);
                soDetail.setState(0);
                soDetailService.save(soDetail);
            }
        }
    }

    @Override
    public List<SoMasterDto> findList3(SoMasterCriteria criteria) {
        return soMasterMapper.findList3(criteria);
    }

    /**
     * 获取任务数据
     *
     * @param
     * @return
     */
    @Override
    public List<SoMasterVo> alignList(QueryCriteria criteria) {
        return baseMapper.alignList(criteria);
    }

    /**
     * 齐套提交
     *
     * @param soDetailVo
     */
    @Override
    public void submitQitao(SoDetailVo soDetailVo) {
//
//        //借料项
//        List<BillOutDetailBO> billOutDetailBOS = soDetailVo.getBillOutDetailBOS().stream().filter(item -> ObjectUtil.isNotEmpty(item.getNumber())).collect(Collectors.toList());
//        //借料项全部数
//        double sum = billOutDetailBOS.stream().mapToDouble(BillOutDetailBO::getNumber).sum();
//        if (sum == 0) {
//            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "借料数量为空");
//        }
//        //全部项
//        SoDetail soDetail = soDetailVo.getAll().get(0);
//        Map<String, Object> soDetil = baseMapper.findByDetilId(soDetail.getSoDetailId());
//        Inventory inventory = new Inventory();
//        //todo 转换入库,
//        this.copyInventory(inventory, soDetil);
//        inventory.setQuantity(sum);
//        inventoryService.save(inventory);
//        //todo 判断改订单号是否库存足够
//        if (this.isQitao(soDetail.getBillNo())) {
//            //修改状态为已齐套
//            SoMaster soMaster = soMasterService.getOne(new QueryWrapper<SoMaster>().eq("bill_no", soDetail.getBillNo()));
//            soMaster.setIsVerify(1);
//            soMasterService.updateById(soMaster);
//        }
//        //
//        if (soDetail.getOrderQuantity() - soDetail.getPickQuantity() < sum) {
//            throw new ServiceException(CommonCode.PARAMETER_ERROR, "借料数量大于差异数量");
//        }
//        //回传ERP
//        OrderToErpBO orderToErpBO = pushErpBean(billOutDetailBOS);
//        pushErpService.pushIMBIll(orderToErpBO);
    }


//    public OrderToErpBO pushErpBean(List<BillOutDetailBO> detailBOS) {
//        OrderToErpBO orderToErpBO = new OrderToErpBO();
//        orderToErpBO.setBillTypeId(29);
//        orderToErpBO.setRob(true);
//        orderToErpBO.setBillNo("12456");
//        orderToErpBO.setSourceBillTypeId(251300022);
////        orderToErpBO.setStockId(45795);
////        orderToErpBO.setCategoryId2(950901);
////        orderToErpBO.setCategoryId3(0);
//
//        List<OrderDetailBO> details = new ArrayList<>();
//
//        detailBOS.forEach(item -> {
//            OrderDetailBO orderDetailBO = new OrderDetailBO();
//            orderDetailBO.setSourceBillId(item.getId());//源单据id
//            orderDetailBO.setSourceBillDetailRowIndex(item.getRowIndex());//行号
//            orderDetailBO.setAuxPropId(item.getAuxPropId());//辅助类型id
//            orderDetailBO.setBatchNo(item.getBatchNo()); //批次
//            orderDetailBO.setQty(item.getNumber());//数量
////            orderDetailBO.setShelfLifeDays(100);//天数
//            orderDetailBO.setBatchNo(item.getBatchNo()); //计划跟踪号
////            orderDetailBO.setStockPlaceId(1);
//            orderDetailBO.setStockId(495);
//            orderDetailBO.setStockId2(505);
//            details.add(orderDetailBO);
//        });
//        orderToErpBO.setDetails(details);
//        return orderToErpBO;
//    }

//    public boolean isQitao(String billNo) {
//        List<SoDetail> soDetailList = soDetailService.list(new QueryWrapper<SoDetail>().in("bill_no", billNo));
//        Set<String> itemCodeSet = soDetailList.stream().map(SoDetail::getItemCode).collect(Collectors.toSet());
//        List<Inventory> inventoryList = inventoryService.list(new QueryWrapper<Inventory>().in("item_code", itemCodeSet));
//        for (SoDetail soDetail : soDetailList) {
//            // //货主id 88货主Id默认为 -1 自有, code SYS_MINE
//            soDetail.setMarginQty(soDetailService.putNumber(inventoryList, soDetail.getItemCode(), -1));
//        }
//        List<SoDetail> soDetails = soDetailService.lendDetail(soDetailList);
//        return soDetails.size() == soDetailList.size();
//    }
//
//    public void copyInventory(Inventory inventory, Map<String, Object> map) {
//        inventory.setWareId(Integer.valueOf(map.get("wareId").toString()));
//        inventory.setWareName(map.get("wareName").toString());
//        inventory.setOrganizationId(Integer.valueOf(map.get("organizationId").toString()));
//        inventory.setOrganizationName(map.get("organizationName").toString());
//        inventory.setItemCode(map.get("itemCode").toString());
//        inventory.setItemName(map.get("itemName").toString());
//        inventory.setBillNo(map.get("billNo").toString());
//    }


    @Override
    @Transactional
    public void TjRgOutRecord(RgProdOutRecord rgProdOutRecord, String userName) {
        // 修改状态为出库
        rgProdOutRecord.setStatus(4000);
        rgProdOutRecordService.saveOrUpdate(rgProdOutRecord);
        // 回传给erp
        // 封装数据
        // 修改状态为出库
        SDPackingBo sdPackingBo = new SDPackingBo();
        sdPackingBo.setAgreementNo(rgProdOutRecord.getAgreementNo());
        sdPackingBo.setPackingNo(rgProdOutRecord.getPackingNo());
        // 0=计划； 1000=生产； 2000=检验； 4000=出库； -1=作废
        sdPackingBo.setStatus(4000);
        sdPackingBo.setUserName(userName);
        // 回传ERP
        pushErpService.sDPacking(sdPackingBo);
    }

    /**
     * 根据生产任务判断是否需要齐套
     *
     * @param yieldBill
     * @return
     */
    @Override
    public Boolean dispatch(String yieldBill) {
        Map<String, Double> map = baseMapper.dispatch(yieldBill);
        Integer asnState = baseMapper.asnState(yieldBill);
        return ObjectUtil.isEmpty(map) || (map.get("deliveryQuantity") <= map.get("orderQuantity") && Optional.ofNullable(asnState).orElse(0) != 0);
    }

    /**
     * 修改分配状态
     *
     * @param soMaster
     */
    @Override
    public void updateState(SoMaster soMaster) {
        List<SoDetail> soDetails = soDetailService.list(new QueryWrapper<SoDetail>().eq("bill_no", soMaster.getBillNo()));
        double orderSum = soDetails.stream().mapToDouble(SoDetail::getOrderQuantity).sum();
        double allSum = soDetails.stream().mapToDouble(SoDetail::getAllottedQuantity).sum();
        Integer state = 0;
        if (orderSum <= allSum) {
            state = 4;
        } else {
            state = 3;
        }
        soMaster.setState(state);
        updateById(soMaster);
    }

    @Override
    public List<SoMaster> listByOrder(CurrentUser currentUser, Integer wareId) {
        QueryWrapper<SoDetail> queryWrapper = new QueryWrapper();
        queryWrapper
                .in(currentUser.getIsAdmin() != 1, "pick_user_id", currentUser.getUserId())
                .apply("pick_quantity<allotted_quantity");

        List<SoDetail> list = soDetailService.list(queryWrapper);
        Set<String> billNos = list.stream().map(SoDetail::getBillNo).collect(Collectors.toSet());
        if (ObjectUtil.isEmpty(billNos)) {
            return null;
        }
        return list(new QueryWrapper<SoMaster>().in("bill_no", billNos).orderByAsc("sort"));
    }

    @Override
    public List<BillOutBO> soErpByDate(String date) {
        return null;
    }

    /**
     * @param soMasters
     */
    @Override
    public void synchronous(List<SoMaster> soMasters) {

        List<SoDetail> allSoDetails = new ArrayList<>();

        List<SoDetail> newSoDetails = soDetailService.syncCurrentData(soMasters);
        if (ObjectUtil.isEmpty(newSoDetails)) {
            newSoDetails = new ArrayList<SoDetail>();
        }
        Set<String> billNos = soMasters.stream().map(item -> item.getBillNo()).collect(Collectors.toSet());
        List<SoDetail> oldSoDetails = soDetailService.list(new QueryWrapper<SoDetail>().in("bill_no", billNos));

        if (ObjectUtil.isEmpty(oldSoDetails)) {
            oldSoDetails = new ArrayList<SoDetail>();
        }
        //对应波次详情
        //老单子新单子合并
        allSoDetails.addAll(oldSoDetails);
        allSoDetails.addAll(newSoDetails);
        //行号可能重复，不能作为唯一条件去重
        Map<SoDetail, SoDetail> newMap = newSoDetails.stream()
                .collect(Collectors.toMap(item -> item, soDetail -> soDetail, (oldValue, newValue) -> newValue));
        //新单子老单子合并
        Map<SoDetail, SoDetail> oldMap = oldSoDetails.stream()
                .collect(Collectors.toMap(item -> item, soDetail -> soDetail, (oldValue, newValue) -> newValue));
        //3.根据明细行去获取
        soDetailService.contrastSoDetail(allSoDetails, newMap, oldMap);
    }

    @Override
    public Integer findCustomerId(String billNo) {
        return baseMapper.customerId(billNo);

    }

    /**
     * 调入仓库
     *
     * @param billNo
     * @return
     */
    @Override
    public Integer findtoErpId(String billNo) {

        return baseMapper.findtoErpId(billNo);
    }

    @Override
    public long findCount(SoMasterCriteria criteria) {

        return baseMapper.findCount(criteria);
    }

    @Autowired
    private CrmDeptAreaService crmDeptAreaService;

    /**
     * 批量分配
     *
     * @param ids
     * @param currentUser
     */
    @Override
    public void suggest(String ids, CurrentUser currentUser) {
        List<String> detailIds = (List<String>) Arrays.asList(ids.split(","));
        List<SoDetail> soDetails = soDetailService.listByIds(detailIds);
        SoMaster soMaster = soMasterService.getOneByField("bill_no", soDetails.listIterator().next().getBillNo());
//        List<Integer> areaIds = soDetails.stream().map(item -> item.getStockId()).collect(Collectors.toList());
        List<Integer> areaIds = crmDeptAreaService.listByDeptId(soMaster.getDeptId());
        if (ObjectUtil.isEmpty(areaIds)) {
            return;
        }
        for (SoDetail soDetail : soDetails) {
            //只需要对未完全分配的进行拣货推荐：计划数大于已分配数
            if (soDetail.getOrderQuantity() > soDetail.getAllottedQuantity()) {
                //找到满足条件的（物料，批次）可用库存
                InventoryCriteria inventoryCriteria = new InventoryCriteria();
//                if (ObjectUtil.isNotEmpty(areaIds)) {
                inventoryCriteria.setAreaIds(areaIds);
//                }
                inventoryCriteria.setItemCode(soDetail.getItemCode());
                inventoryCriteria.setWareId(soMaster.getWareId());
                inventoryCriteria.setOrganizationId(soMaster.getOrganizationId());
                List<InventorySelectDto> inventoryDtos = inventoryService.findCanBeOutOfStock(inventoryCriteria);
                // 增加判断这里判断是否有库存--没有库存抛异常(张宇)
                if (inventoryDtos.size() < 1) {
                    continue;
                }
                soDetail.setPickUserId(currentUser.getUserId());
                soDetail.setPickUserName(currentUser.getUserName());
                pickTaskService.createPickTask(soMaster, soDetail, inventoryDtos);
            }
        }





    }

    @Override
    public void suggestAndPush(String billNo) {
        List<PickTask> pickTaskList = new ArrayList<>();
        SoMaster soMaster = getOne(new QueryWrapper<SoMaster>()
                .eq("bill_no", billNo)
                .last("limit 1")
        );
        List<SoDetail> soDetailList = soDetailService.list(new QueryWrapper<SoDetail>()
                .eq("bill_no", billNo)
        );
        List<Integer> areaIds = soDetailList.stream().map(SoDetail::getStockId).collect(Collectors.toList());
        Set<String> itemCodes = soDetailList.stream().map(SoDetail::getItemCode).collect(Collectors.toSet());
        List<ItemInfo> itemInfos = itemInfoService.list(new QueryWrapper<ItemInfo>()
                .in("item_code", itemCodes)
        );
        Map<String, ItemInfo> itemInfoMap = convertMap(itemInfos, ItemInfo::getItemCode);
        InventoryCriteria inventoryCriteria = new InventoryCriteria();
        inventoryCriteria.setAreaIds(areaIds);
        inventoryCriteria.setItemCodes(itemCodes);
        inventoryCriteria.setWareId(285);
        inventoryCriteria.setOrganizationId(-1);
        List<InventorySelectDto> inventoryDtos = inventoryService.findCanBeOutOfStock(inventoryCriteria);
        Map<Integer, InventorySelectDto> invMap = convertMap(inventoryDtos, InventorySelectDto::getInventoryId);
        List<OutDetail> outDetails = new ArrayList<>();
        for (SoDetail soDetail : soDetailList) {
            //查找对应库存
            List<InventorySelectDto> invs = inventoryDtos.stream().filter(item -> soDetail.getItemCode().equals(item.getItemCode())).collect(Collectors.toList());
            //Step2.生成拣货任务
            double remainAllotQty;
            //有预分配数量则取预分配数量，没有则全部分配
            remainAllotQty = soDetail.getOrderQuantity() - soDetail.getAllottedQuantity();
            if (remainAllotQty <= 0) {
                continue;
            }
            for (InventorySelectDto inv : invs) {
                if (inv.getAllotQuantity() <= 0) {
                    inv.setAllotQuantity(0.00);
                }
                double canBeQuantity = inv.getQuantity() - inv.getAllotQuantity() - inv.getFreezeQuantity();
                if (canBeQuantity <= 0) {
                    continue;
                }
                //Step2.1新建拣货任务  根据波次明细初始化
                PickTask pickTask = new PickTask(
                        soDetail.getSoDetailId(),
                        soMaster.getSoMasterId(),
                        soMaster.getWareId(),
                        soMaster.getWareName(),
                        soMaster.getOrganizationId(),
                        soMaster.getOrganizationName(),
                        inv.getAreaCode(),
                        inv.getAreaName(),
                        inv.getShelfCode(),
                        inv.getShelfName(),
                        inv.getCellCode(),
                        inv.getCellName(),
                        inv.getItemCode(),
                        inv.getItemName(),
                        inv.getBatchId(),
                        inv.getBatchName(),
                        inv.getBoxCode(),
                        inv.getLpn(),
                        soDetail.getPackDetailId(),
                        soDetail.getPackDescribe(),
                        0.00,
                        5,
                        inv.getInventoryId(),
                        1,
                        soDetail.getImgUrl()
                );
                pickTask.setPickTaskCode(codeRuleService.generateCodeByRedis(SystemManageConstant.CODE_RULE_PICK));
                //遍历可用库存，分配可用数量 (引申：对于复杂场景，这里可用动态规划的算法)
                if (canBeQuantity >= remainAllotQty) {


                    //1)可分配数量 大于出库任务明细待分配数量 出库任务明细分配完毕
                    pickTask.setPickQuantity(remainAllotQty);
                    soDetail.setAllottedQuantity(soDetail.getAllottedQuantity() + pickTask.getPickQuantity());
                    soDetail.setPickQuantity(soDetail.getPickQuantity() + pickTask.getPickQuantity());
                    soDetail.setDeliveryQuantity(soDetail.getDeliveryQuantity() + pickTask.getPickQuantity());

                    OutDetail outDetail = new OutDetail();
                    outDetail.setDeliveryQuantity(canBeQuantity);
                    outDetail.setDeliveryQuantity(pickTask.getPickQuantity()); //数量
                    outDetail.setBatchName(inv.getBatchName());
                    outDetail.setErpAreaId(inv.getErpAreaId());
                    outDetail.setToErpId(335599);
                    outDetail.setItemId(itemInfoMap.get(soDetail.getItemCode()).getErpItemId());

                    outDetails.add(outDetail);
                    //记录波次明细的已分配数量 记录状态为已分配
                    InventorySelectDto invDto = invMap.get(inv.getInventoryId());
                    invDto.setQuantity(invDto.getQuantity() - pickTask.getPickQuantity());
                    invDto.setTransRatio(1.0);
                    pickTask.setInventoryId(inv.getInventoryId());
                    pickTaskList.add(pickTask);
                    //分配完成直接跳出循环
                    //记录状态
                    if (ObjectUtil.equal(soDetail.getOrderQuantity(), soDetail.getAllottedQuantity())) {
                        soDetail.setState(WareTaskConstant.WAVE_STATE_ALL_ALOT);
                    } else {
                        soDetail.setState(WareTaskConstant.WAVE_STATE_PICKING);
                    }
                    break;
                } else {
                    //2)可分配数量不够完全分配  则将可分配数量全部分配出去
                    OutDetail outDetail = new OutDetail();
                    outDetail.setDeliveryQuantity(canBeQuantity);
                    outDetail.setDeliveryQuantity(pickTask.getPickQuantity()); //数量
                    outDetail.setBatchName(inv.getBatchName());
                    outDetail.setErpAreaId(inv.getErpAreaId());
                    outDetail.setToErpId(335599);
                    outDetail.setItemId(itemInfoMap.get(soDetail.getItemCode()).getErpItemId());
                    outDetails.add(outDetail);

                    pickTask.setPickQuantity(canBeQuantity);
                    soDetail.setAllottedQuantity(soDetail.getAllottedQuantity() + canBeQuantity);
                    soDetail.setPickQuantity(soDetail.getPickQuantity() + canBeQuantity);
                    soDetail.setDeliveryQuantity(soDetail.getDeliveryQuantity() + canBeQuantity);
                    if (ObjectUtil.equal(soDetail.getOrderQuantity(), soDetail.getAllottedQuantity())) {
                        soDetail.setState(WareTaskConstant.WAVE_STATE_ALL_ALOT);
                    } else {
                        soDetail.setState(WareTaskConstant.WAVE_STATE_PICKING);
                    }
                    InventorySelectDto invDto = invMap.get(inv.getInventoryId());
//                    invDto.setAllotQuantity(invDto.getAllotQuantity() + pickTask.getPickQuantity());
                    invDto.setQuantity(invDto.getQuantity() - pickTask.getPickQuantity());
                    invDto.setTransRatio(1.0);
//                    inventoryService.updateById(inv);
                    pickTask.setInventoryId(inv.getInventoryId());
                    pickTaskList.add(pickTask);
                    remainAllotQty -= canBeQuantity;
                }
                //记录状态
                if (ObjectUtil.equal(soDetail.getOrderQuantity(), soDetail.getAllottedQuantity())) {
                    soDetail.setState(WareTaskConstant.WAVE_STATE_ALL_ALOT);
                } else {
                    soDetail.setState(WareTaskConstant.WAVE_STATE_PICKING);
                }
            }

        }
        List<Inventory> updateInv = new ArrayList<>();
        for (InventorySelectDto inventoryDto : inventoryDtos) {
            Inventory inventory = new Inventory();
            BeanUtils.copyProperties(inventoryDto, inventory);
            updateInv.add(inventory);
        }
        inventoryService.updateBatchById(updateInv);
        //保存生成的拣货任务
        pickTaskService.saveBatch(pickTaskList);
        //更新波次明细状态 和 已分配数量
        //更新波次状态
        soDetailService.updateBatchById(soDetailList);
        if (ObjectUtil.isEmpty(outDetails)) {
            return;
        }
        soMaster.setSoType(1168110);
        strategyErpService.resolveSo(soMaster, outDetails, new BaseAssist());
    }



}
